package com.hyk.commonLib.common.aop;

import com.hyk.commonLib.common.utils.ReflectUtils;
import com.hyk.commonLib.common.utils.viewModel.BaseObservableModel;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

import java.util.HashSet;
import java.util.Set;

@Aspect
public class ModelAspect {
    /**
     * @see BaseObservableModel.PropertiesChanged
     */
    @After("execution(@com.hyk.commonLib.common.utils.viewModel.BaseObservableModel.PropertiesChanged * *(..))")
    public void notifyPropertiesChanged(JoinPoint joinPoint) {
        BaseObservableModel.PropertiesChanged propertiesChangedAnno = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(BaseObservableModel.PropertiesChanged.class);
        Object target = joinPoint.getTarget();
        if (!(target instanceof BaseObservableModel)) {
            throw new RuntimeException("@PropertiesChanged 注解只能用于 BaseObservableModel 及 其子类 的方法上");
        }
        if (propertiesChangedAnno == null) {
            throw new RuntimeException("不可能的！");
        }

        Set<Integer> idList = new HashSet<>();
        String[] propertyNames = propertiesChangedAnno.names();
        for (String propertyName : propertyNames) {
            Integer brId = ReflectUtils.getStaticField(com.hyk.commonLib.BR.class, propertyName);
            if (brId != null && brId != 0) idList.add(brId);
        }
        int[] brIds = propertiesChangedAnno.brIds();
        for (int brId : brIds) {
            idList.add(brId);
        }
        if (propertiesChangedAnno.value()) {
            String methodName = ((MethodSignature) joinPoint.getSignature()).getMethod().getName();
            String fieldName = methodName.substring(3);
            fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
            Integer brId = ReflectUtils.getStaticField(com.hyk.commonLib.BR.class, fieldName);
            idList.add(brId);
        }

        idList.remove(0);
        idList.remove(null);
        for (Integer id : idList) {
            ((BaseObservableModel) target).notifyPropertyChanged(id);
        }
    }

    public static ModelAspect aspectOf() {
        return new ModelAspect();
    }
}
